{T}

SVG 动画基础入门

我们生活在一个数字时代,设备种类繁多。Web 前端工程师对此了如指掌。当你面对不同和多样的屏幕尺寸、宽高比、分辨率和颜色设置时,最难实现的可能就是在各个设备上获得一致的内容体验。实现一致性的解决方案之一是利用可缩放矢量图形(SVG)的图像。具有 .svg 文件格式的图像尽管存在一些限制,却带来诸多优势,比如在不增加加载时间负担的同时为 Web 应用或网站创建视觉上引人入胜的视外观。

可缩放矢量图形(SVG)在 Web 开发中已经是一个重要的组成部分,原因是它们具有矢量属性,可以在放大或缩小时不损失质量。由于其 XML 格式,它们可以进行压缩和优化。它们还可以轻松进行编辑、样式化、动画化和以编程方式进行更改。

最终,SVG 是一种标记语言。就像我们可以使用 CSS 和 JavaScript 来增加 HTML 一样,我们也可以在 SVG 上使用它们。我们可以为图形元素添加特色和装饰,添加交互,并塑造真正令人愉悦和难忘的用户体验。在构建项目时,这是一个可选但关键的细节,因此 SVG 在超出其基本图形用例之外往往被轻视。

事实上,可以使用 CSS 或 JavaScript 对 SVG 进行动画处理,使它们更具吸引力。这意味着,Web 开发者可以将 SVG 和 CSS 或 JavaScript 结合起来,发挥它们的潜力,在不依赖外部库的情况下创建动画效果。

在这节课,我将和大家一起来探讨 SVG 动画的最基础部分。

什么是 SVG ?

SVG 是可缩放矢量图形(Scalable Vector Graphics)的缩写,它是一种用于描述二维矢量图形的 XML(可扩展标记语言)标准,有点类似于 HTML 的工作方式。SVG 定义了不同的元素,用于表示可以在 XML (可扩展标记语言)文本文件中组合熟悉几何形状,从而生成二维图形。与位图图像(如 JPEG、PNG、GIF 等)不同,SVG 图形是基于矢量的,因此可以无损地缩放到任意大小而不失真。SVG 图形通常由图形元素(例如 <polygon><ellipse><circle><rect><path> 等)、文本(<text>)和其他可视化效果组成,可以通过文本编辑器进行创建和编辑。

SVG 有以下一些关键特点:

  • 可缩放性: SVG 图形可以无损地缩放到任意大小而不失真,因为它是基于矢量的。
  • 文本格式: SVG 使用 XML 格式,因此它是一种纯文本格式,易于创建、编辑和理解。这也使得 SVG 图形可以嵌入到 HTML 文档中。
  • 可编辑性: 由于 SVG 是基于文本的,可以轻松地通过文本编辑器或专业的图形编辑软件进行修改和编辑。
  • 支持文本和图形混合: SVG 允许在图形中嵌入文本,这使得它非常适合用于创建数据可视化、图表等场景。
  • 图形元素丰富: SVG 提供了丰富的图形元素,包括线条、圆形、矩形、路径等,可以通过这些元素创建各种复杂的图形。
  • 支持动画: SVG 支持通过 CSS 或 JavaScript 添加动画效果,使得图形可以呈现出生动的交互效果。
  • 与 CSS 和 JavaScript 的集成: 可以使用 CSS 样式对 SVG 进行样式化,同时也可以通过 JavaScript 实现更高级的交互和动态效果。
  • 支持事件处理: SVG 允许通过 JavaScript 添加事件处理器,实现与用户交互的功能。
  • 广泛浏览器支持: 大多数现代浏览器都支持 SVG,使得它成为在 Web 上创建矢量图形的流行选择。
  • 广泛用途: SVG 广泛用于 Web 开发,特别是在需要响应式设计和可缩放图形的场景中。它常被用于创建图标、图表、地图、动画等。

总的来说,SVG 是一种灵活、可扩展、易于使用和编辑的图形格式,适用于许多不同的应用领域,特别是 Web 开发中。

如何获取 SVG ?

对于 Web 开发者而言,有几种不同的方式可以获得 SVG,这取决于你的需求和使用场景。

手动创建

这是最硬核的一种方式,你可以使用文本编辑器手动创建 SVG 代码,这是一种基于 XML 的文本格式,你可以编写或复制现有的 SVG 代码,然后将其保存为 .svg 格式的文件。

手动创建 SVG 有一个必要的前提条件,那就是你对 SVG 知识很了解。例如,你可以使用 SVG 的一些元素来创建基本形状:

  • <circle>:创建一个圆
  • <ellipse>:创建一个椭圆
  • <line>:创建一条直线
  • <polyline>:创建一系列连接的直线
  • <polygon>:创建一个多边形
  • <path>:创建任意形状的路径

来看一个简单的示例,使用 <ellipse> 绘制一个椭圆:

SVG
<ellipse cx="400" cy="300" rx="250" ry="150" />

你也可以使用 <path> 绘制一些复杂的图形,例如下面这个心形:

SVG
<svg viewBox="0 0 1024 1024" width="400" height="400">
    <path d="M718.784 98.464a34.432 34.432 0 1 0 0 68.928 137.984 137.984 0 0 1 137.856 137.856 34.464 34.464 0 1 0 68.928 0 207.04 207.04 0 0 0-206.784-206.784zM512 990.592C209.568 840.544 29.536 585.344 29.536 305.216c0-152 123.68-275.68 275.68-275.68 55.616 0 109.472 17.152 155.136 48.448a342.912 342.912 0 0 0-86.208 227.232 34.464 34.464 0 0 0 68.928 0 274.88 274.88 0 0 1 109.728-219.616l3.776-2.784a259.392 259.392 0 0 1 21.664-14.336c5.536-3.296 11.232-6.432 16.992-9.376l6.08-2.944c5.504-2.592 11.104-5.088 16.768-7.296 2.528-0.992 5.088-1.888 7.648-2.816 5.344-1.92 10.72-3.776 16.192-5.376 3.232-0.928 6.56-1.728 9.856-2.56 4.896-1.248 9.856-2.528 14.848-3.488 4.512-0.864 9.12-1.44 13.76-2.112 3.936-0.544 7.872-1.248 11.808-1.664 8.768-0.832 17.6-1.344 26.56-1.344 152 0 275.68 123.68 275.68 275.68 0 280.128-180.032 535.328-482.464 685.376z"></path>
</svg>

Demo 地址:https://codepen.io/airen/full/oNVyPEw

<path> 是最多才多艺的 SVG 元素。它可用于绘制任何可能的线条和形状,包括但不限于我们常见的基本形状,例如直线、连接线、曲线、多边形、矩形、圆形和椭圆形等。实际上,每个基本形状(<circle><ellipse><rect><line><polyline><polygon>)都可以用 <path> 元素来描述。更重要的是,有许多可以用 <path> 创建但不能用其他任何SVG元素创建的形状,例如上面的心形。

SVG 的 <path> 包含了很多命令,比如光标 C 、移动 M 、直线 L 、贝塞尔曲线 Q 和弧线 A 等。你可以通过 @nandafyi 写的在线工具来进一步的理解用于 <path> 元素上各种命令:

Tools URL:https://www.nan.fyi/svg-paths

通过命令来绘制复杂的图形,对于大多数 Web 开发者来说,都不是一件容易的事情,除了需要对所有命令了解之外,还将会涉及大量的数学计算。相对而言,这种方式的成本是很高的,而且也很容易出错。有一种更好的方式是,通过图形编辑(例如 Sketch 、Figma 、Adobe Illustrator、Inkscape 等)软件中的钢笔工具或矢量工具绘制。

SVG 的元素和 HTML 的元素类似,我们可以在 SVG 元素上添加很多属性,例如:

  • fill :设置图形填充色
  • fill-opacity :设置图形填充物的透明度
  • stroke :设置图形轮廓的颜色
  • stroke-dasharray :可控制用来描边的点划线的图案范式式
  • stroke-dashoffset : 属性指定了 dash 模式到路径开始的距离离
  • 等等

比如,我们在上面示例的基础上给 <path> 设置一些属性:

SVG
<svg viewBox="0 0 1024 1024" width="400" height="400">
  <path 
        fill="oklch(0.6 0.26 29.61)"
        stroke="oklch(0.43 0.29 264.81)"
        stroke-width="10px"
        stroke-dasharray="60 20"
        stroke-linejoin="miter"
        stroke-linecap="round"
        d="M718.784 98.464a34.432 34.432 0 1 0 0 68.928 137.984 137.984 0 0 1 137.856 137.856 34.464 34.464 0 1 0 68.928 0 207.04 207.04 0 0 0-206.784-206.784zM512 990.592C209.568 840.544 29.536 585.344 29.536 305.216c0-152 123.68-275.68 275.68-275.68 55.616 0 109.472 17.152 155.136 48.448a342.912 342.912 0 0 0-86.208 227.232 34.464 34.464 0 0 0 68.928 0 274.88 274.88 0 0 1 109.728-219.616l3.776-2.784a259.392 259.392 0 0 1 21.664-14.336c5.536-3.296 11.232-6.432 16.992-9.376l6.08-2.944c5.504-2.592 11.104-5.088 16.768-7.296 2.528-0.992 5.088-1.888 7.648-2.816 5.344-1.92 10.72-3.776 16.192-5.376 3.232-0.928 6.56-1.728 9.856-2.56 4.896-1.248 9.856-2.528 14.848-3.488 4.512-0.864 9.12-1.44 13.76-2.112 3.936-0.544 7.872-1.248 11.808-1.664 8.768-0.832 17.6-1.344 26.56-1.344 152 0 275.68 123.68 275.68 275.68 0 280.128-180.032 535.328-482.464 685.376z"></path>
</svg>

你将看到的效果如下:

Demo 地址:https://codepen.io/airen/full/poYKxby

再次强调一下,手动创建 SVG 需要对 SVG 有一定的熟悉程度。上面所提到的仅仅 SVG 中最基础的部分,如果你想更进一步了解和学习 SVG 的话,那么你可以通过 SVG 的规范MDN 的相关文档学习。快速入门的话,还可以移步阅读 @Hunor Márton Borbély 写的 SVG 系列教程:

SVG Tutorial:https://svg-tutorial.com/

图形编辑软件

如果你对 SVG 相关的知识不太了解,那么通过图形编辑软件获取 SVG 是较为简单的一种方式。该方式的前提条件是你对图形编辑软件有一定的了解,并且你能通过图形编辑软件设计出你需要的图形。如果你不具备一定的设计能力,则需要通过与 Web 设计师一起合作。这意味着,你可以通过图形编辑软件将设计师设计好的图形导出 .svg 文件。

拿 Figma 图形编辑软件为例,假设你使用 Figma 设计好了自己需要的图形,那么就可以按下图的方式将图形导出 .svg 文件:

然后使用文本编辑器打开导出的 .svg 文件,你就获得了相关的 SVG 代码:

SVG
<svg width="1668" height="614" viewBox="0 0 1668 614" fill="none" xmlns="http://www.w3.org/2000/svg">
    <path fill-rule="evenodd" clip-rule="evenodd" d="M1575.43 266.743C1592.66 236.188 1590.24 198.267 1575.53 160.793C1560.82 123.312 1533.79 86.2031 1501.64 57.1904C1469.51 28.1819 1432.21 7.22623 1396.97 2.12107C1361.68 -2.98934 1328.45 7.7914 1304.58 42.2129C1271.42 90.039 1232.67 131.745 1199.64 167.283C1185.39 182.626 1172.2 196.819 1160.99 209.859C1151.7 220.663 1143.77 230.678 1137.73 239.894C1131.69 249.107 1127.52 257.549 1125.77 265.207C1124.02 272.878 1124.71 279.781 1128.41 285.864C1132.09 291.934 1138.74 297.122 1148.8 301.457C1158.64 305.704 1166.72 315.064 1173.95 328.104C1181.18 341.136 1187.52 357.772 1193.93 376.472C1196.6 384.267 1199.28 392.419 1202.04 400.814L1202.04 400.831L1202.04 400.833C1212.52 432.683 1224.14 468.025 1240.67 500.598C1261.57 541.777 1290.36 578.607 1334.69 598.453C1379.03 618.301 1438.82 621.122 1521.65 594.474C1563.04 581.155 1593.88 567.939 1616.27 554.763C1638.66 541.589 1652.65 528.437 1660.3 515.233C1675.63 488.759 1665.4 462.304 1647.1 435.59C1638.88 423.594 1629.01 411.505 1619.04 399.301C1617.9 397.908 1616.77 396.513 1615.63 395.117C1604.52 381.481 1593.51 367.694 1584.71 353.684C1567.11 325.667 1558.44 296.88 1575.43 266.743ZM1305.41 42.7828C1329.04 8.70501 1361.87 -1.95116 1396.82 3.11075C1431.81 8.1779 1468.92 29.0037 1500.97 57.9328C1533.02 86.8577 1559.95 123.842 1574.6 161.158C1589.25 198.48 1591.58 236.059 1574.56 266.252C1557.3 296.865 1566.19 326.077 1583.86 354.216C1592.7 368.285 1603.74 382.115 1614.85 395.749C1615.43 396.455 1616 397.16 1616.58 397.865L1618.27 399.931C1628.24 412.141 1638.08 424.196 1646.27 436.155C1664.53 462.817 1674.45 488.8 1659.43 514.732C1651.9 527.732 1638.08 540.775 1615.76 553.901C1593.46 567.026 1562.7 580.216 1521.34 593.522C1438.66 620.123 1379.14 617.256 1335.1 597.541C1291.06 577.824 1262.41 541.217 1241.56 500.146C1225.07 467.647 1213.48 432.4 1203.01 400.556C1200.24 392.145 1197.55 383.971 1194.87 376.148C1188.47 357.443 1182.1 340.734 1174.83 327.619C1167.56 314.51 1159.34 304.917 1149.19 300.539C1139.25 296.249 1132.8 291.171 1129.26 285.345C1125.73 279.531 1125.04 272.907 1126.75 265.429C1128.46 257.938 1132.56 249.611 1138.57 240.442C1144.58 231.278 1152.47 221.301 1161.75 210.511C1172.92 197.52 1186.08 183.356 1200.32 168.032L1200.32 168.03C1233.36 132.473 1272.2 90.6683 1305.41 42.7828Z" fill="black"/>
    <path d="M480 305C480 437.548 372.548 545 240 545C107.452 545 0 437.548 0 305C0 172.451 107.452 64.9998 240 64.9998C372.548 64.9998 480 172.451 480 305Z" fill="black"/>
    <path d="M757 64.9998L810.883 230.836H985.254L844.185 333.328L898.068 499.164L757 396.672L615.932 499.164L669.815 333.328L528.746 230.836H703.117L757 64.9998Z" fill="black"/>
</svg>

另外一种方式是,你还可以直接在图形编辑软件中以 SVG 代码方式复制图形,然后在文本编辑软件中粘贴所复制的代码,同样可以获得 SVG 相关的代码。

SVG
<svg width="1668" height="614" viewBox="0 0 1668 614" fill="none" xmlns="http://www.w3.org/2000/svg">
    <path fill-rule="evenodd" clip-rule="evenodd" d="M1575.43 266.743C1592.66 236.188 1590.24 198.267 1575.53 160.793C1560.82 123.312 1533.79 86.2031 1501.64 57.1904C1469.51 28.1819 1432.21 7.22623 1396.97 2.12107C1361.68 -2.98934 1328.45 7.7914 1304.58 42.2129C1271.42 90.039 1232.67 131.745 1199.64 167.283C1185.39 182.626 1172.2 196.819 1160.99 209.859C1151.7 220.663 1143.77 230.678 1137.73 239.894C1131.69 249.107 1127.52 257.549 1125.77 265.207C1124.02 272.878 1124.71 279.781 1128.41 285.864C1132.09 291.934 1138.74 297.122 1148.8 301.457C1158.64 305.704 1166.72 315.064 1173.95 328.104C1181.18 341.136 1187.52 357.772 1193.93 376.472C1196.6 384.267 1199.28 392.419 1202.04 400.814L1202.04 400.831L1202.04 400.833C1212.52 432.683 1224.14 468.025 1240.67 500.598C1261.57 541.777 1290.36 578.607 1334.69 598.453C1379.03 618.301 1438.82 621.122 1521.65 594.474C1563.04 581.155 1593.88 567.939 1616.27 554.763C1638.66 541.589 1652.65 528.437 1660.3 515.233C1675.63 488.759 1665.4 462.304 1647.1 435.59C1638.88 423.594 1629.01 411.505 1619.04 399.301C1617.9 397.908 1616.77 396.513 1615.63 395.117C1604.52 381.481 1593.51 367.694 1584.71 353.684C1567.11 325.667 1558.44 296.88 1575.43 266.743ZM1305.41 42.7828C1329.04 8.70501 1361.87 -1.95116 1396.82 3.11075C1431.81 8.1779 1468.92 29.0037 1500.97 57.9328C1533.02 86.8577 1559.95 123.842 1574.6 161.158C1589.25 198.48 1591.58 236.059 1574.56 266.252C1557.3 296.865 1566.19 326.077 1583.86 354.216C1592.7 368.285 1603.74 382.115 1614.85 395.749C1615.43 396.455 1616 397.16 1616.58 397.865L1618.27 399.931C1628.24 412.141 1638.08 424.196 1646.27 436.155C1664.53 462.817 1674.45 488.8 1659.43 514.732C1651.9 527.732 1638.08 540.775 1615.76 553.901C1593.46 567.026 1562.7 580.216 1521.34 593.522C1438.66 620.123 1379.14 617.256 1335.1 597.541C1291.06 577.824 1262.41 541.217 1241.56 500.146C1225.07 467.647 1213.48 432.4 1203.01 400.556C1200.24 392.145 1197.55 383.971 1194.87 376.148C1188.47 357.443 1182.1 340.734 1174.83 327.619C1167.56 314.51 1159.34 304.917 1149.19 300.539C1139.25 296.249 1132.8 291.171 1129.26 285.345C1125.73 279.531 1125.04 272.907 1126.75 265.429C1128.46 257.938 1132.56 249.611 1138.57 240.442C1144.58 231.278 1152.47 221.301 1161.75 210.511C1172.92 197.52 1186.08 183.356 1200.32 168.032L1200.32 168.03C1233.36 132.473 1272.2 90.6683 1305.41 42.7828Z" fill="black"/>
    <path d="M480 305C480 437.548 372.548 545 240 545C107.452 545 0 437.548 0 305C0 172.451 107.452 64.9998 240 64.9998C372.548 64.9998 480 172.451 480 305Z" fill="black"/>
    <path d="M757 64.9998L810.883 230.836H985.254L844.185 333.328L898.068 499.164L757 396.672L615.932 499.164L669.815 333.328L528.746 230.836H703.117L757 64.9998Z" fill="black"/>
</svg>

注意,不同的图形编辑软件,操作方式可能会略有不同,具体请参阅图形编辑软件的操作文档。

另外,我们可以通过一些工具对图形编辑软件导出的 SVG 代码进行优化。因为,SVG 元素可以像任何其他标记语言一样进行优化,我们可以对其进行缩小并删除不必要的格式和元素数据,可以删除不必要的属性和不可见元素等。

这些优化可以根据你的技术栈自动完成。SVGO 是最流行的用于优化 SVG 的工具,可以轻松集成到几乎任何技术栈中。如果你不想花时间在工程环境中配置 SVGO 的话,你也可以使用 @Jake Archibald 的 SVGOMG 对 SVG 代码进行优化,这也是一个很不错的选择。我自己经常这样使用。

就拿刚才从 Figma 中导出的 .svg 文件为例,我们可以使用 SVGOMG 做一些优化处理:

SVGOMG:https://jakearchibald.github.io/svgomg/

对比一下,使用 SVGOMG 优化前后的差异:

SVG
<!-- 优化前 -->
<svg width="1668" height="614" viewBox="0 0 1668 614" fill="none" xmlns="http://www.w3.org/2000/svg">
    <path fill-rule="evenodd" clip-rule="evenodd" d="M1575.43 266.743C1592.66 236.188 1590.24 198.267 1575.53 160.793C1560.82 123.312 1533.79 86.2031 1501.64 57.1904C1469.51 28.1819 1432.21 7.22623 1396.97 2.12107C1361.68 -2.98934 1328.45 7.7914 1304.58 42.2129C1271.42 90.039 1232.67 131.745 1199.64 167.283C1185.39 182.626 1172.2 196.819 1160.99 209.859C1151.7 220.663 1143.77 230.678 1137.73 239.894C1131.69 249.107 1127.52 257.549 1125.77 265.207C1124.02 272.878 1124.71 279.781 1128.41 285.864C1132.09 291.934 1138.74 297.122 1148.8 301.457C1158.64 305.704 1166.72 315.064 1173.95 328.104C1181.18 341.136 1187.52 357.772 1193.93 376.472C1196.6 384.267 1199.28 392.419 1202.04 400.814L1202.04 400.831L1202.04 400.833C1212.52 432.683 1224.14 468.025 1240.67 500.598C1261.57 541.777 1290.36 578.607 1334.69 598.453C1379.03 618.301 1438.82 621.122 1521.65 594.474C1563.04 581.155 1593.88 567.939 1616.27 554.763C1638.66 541.589 1652.65 528.437 1660.3 515.233C1675.63 488.759 1665.4 462.304 1647.1 435.59C1638.88 423.594 1629.01 411.505 1619.04 399.301C1617.9 397.908 1616.77 396.513 1615.63 395.117C1604.52 381.481 1593.51 367.694 1584.71 353.684C1567.11 325.667 1558.44 296.88 1575.43 266.743ZM1305.41 42.7828C1329.04 8.70501 1361.87 -1.95116 1396.82 3.11075C1431.81 8.1779 1468.92 29.0037 1500.97 57.9328C1533.02 86.8577 1559.95 123.842 1574.6 161.158C1589.25 198.48 1591.58 236.059 1574.56 266.252C1557.3 296.865 1566.19 326.077 1583.86 354.216C1592.7 368.285 1603.74 382.115 1614.85 395.749C1615.43 396.455 1616 397.16 1616.58 397.865L1618.27 399.931C1628.24 412.141 1638.08 424.196 1646.27 436.155C1664.53 462.817 1674.45 488.8 1659.43 514.732C1651.9 527.732 1638.08 540.775 1615.76 553.901C1593.46 567.026 1562.7 580.216 1521.34 593.522C1438.66 620.123 1379.14 617.256 1335.1 597.541C1291.06 577.824 1262.41 541.217 1241.56 500.146C1225.07 467.647 1213.48 432.4 1203.01 400.556C1200.24 392.145 1197.55 383.971 1194.87 376.148C1188.47 357.443 1182.1 340.734 1174.83 327.619C1167.56 314.51 1159.34 304.917 1149.19 300.539C1139.25 296.249 1132.8 291.171 1129.26 285.345C1125.73 279.531 1125.04 272.907 1126.75 265.429C1128.46 257.938 1132.56 249.611 1138.57 240.442C1144.58 231.278 1152.47 221.301 1161.75 210.511C1172.92 197.52 1186.08 183.356 1200.32 168.032L1200.32 168.03C1233.36 132.473 1272.2 90.6683 1305.41 42.7828Z" fill="black"/>
    <path d="M480 305C480 437.548 372.548 545 240 545C107.452 545 0 437.548 0 305C0 172.451 107.452 64.9998 240 64.9998C372.548 64.9998 480 172.451 480 305Z" fill="black"/>
    <path d="M757 64.9998L810.883 230.836H985.254L844.185 333.328L898.068 499.164L757 396.672L615.932 499.164L669.815 333.328L528.746 230.836H703.117L757 64.9998Z" fill="black"/>
</svg>

<!-- 优化后 -->
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 1668 614">
    <path fill="#000" fill-rule="evenodd" d="M1575.43 266.743c17.23-30.555 14.81-68.476.1-105.95-14.71-37.481-41.74-74.59-73.89-103.603-32.13-29.008-69.43-49.964-104.67-55.069-35.29-5.11-68.52 5.67-92.39 40.092-33.16 47.826-71.91 89.532-104.94 125.07-14.25 15.343-27.44 29.536-38.65 42.576-9.29 10.804-17.22 20.819-23.26 30.035-6.04 9.213-10.21 17.655-11.96 25.313-1.75 7.671-1.06 14.574 2.64 20.657 3.68 6.07 10.33 11.258 20.39 15.593 9.84 4.247 17.92 13.607 25.15 26.647 7.23 13.032 13.57 29.668 19.98 48.368 2.67 7.795 5.35 15.947 8.11 24.342V400.833c10.48 31.85 22.1 67.192 38.63 99.765 20.9 41.179 49.69 78.009 94.02 97.855 44.34 19.848 104.13 22.669 186.96-3.979 41.39-13.319 72.23-26.535 94.62-39.711 22.39-13.174 36.38-26.326 44.03-39.53 15.33-26.474 5.1-52.929-13.2-79.643-8.22-11.996-18.09-24.085-28.06-36.289-1.14-1.393-2.27-2.788-3.41-4.184-11.11-13.636-22.12-27.423-30.92-41.433-17.6-28.017-26.27-56.804-9.28-86.941Zm-270.02-223.96c23.63-34.078 56.46-44.734 91.41-39.672 34.99 5.067 72.1 25.893 104.15 54.822 32.05 28.925 58.98 65.909 73.63 103.225 14.65 37.322 16.98 74.901-.04 105.094-17.26 30.613-8.37 59.825 9.3 87.964 8.84 14.069 19.88 27.899 30.99 41.533.58.706 1.15 1.411 1.73 2.116l1.69 2.066c9.97 12.21 19.81 24.265 28 36.224 18.26 26.662 28.18 52.645 13.16 78.577-7.53 13-21.35 26.043-43.67 39.169-22.3 13.125-53.06 26.315-94.42 39.621-82.68 26.601-142.2 23.734-186.24 4.019-44.04-19.717-72.69-56.324-93.54-97.395-16.49-32.499-28.08-67.746-38.55-99.59-2.77-8.411-5.46-16.585-8.14-24.408-6.4-18.705-12.77-35.414-20.04-48.529-7.27-13.109-15.49-22.702-25.64-27.08-9.94-4.29-16.39-9.368-19.93-15.194-3.53-5.814-4.22-12.438-2.51-19.916 1.71-7.491 5.81-15.818 11.82-24.987 6.01-9.164 13.9-19.141 23.18-29.931 11.17-12.991 24.33-27.155 38.57-42.479v-.002c33.04-35.557 71.88-77.362 105.09-125.247Z" clip-rule="evenodd" />
    <path fill="#000" d="M480 305c0 132.548-107.452 240-240 240S0 437.548 0 305C0 172.451 107.452 65 240 65S480 172.45 480 305ZM757 65l53.883 165.836h174.371L844.185 333.328l53.883 165.836L757 396.672 615.932 499.164l53.883-165.836-141.069-102.492h174.371L757 65Z" />
</svg>

并不能发现,优化后的 SVG 代码相比于优化前的 SVG ,少了一个 <path> 元素,但它们最终呈现的结果是一样的:

Demo 地址:https://codepen.io/airen/full/poYZeEq

在线平台或库

通过在线平台或库获取SVG通常是一种简便的方式,这些资源提供了大量免费的、高质量的SVG 图形。例如,你可以通过 iconfontFontAwesome 等在线平台来获取 Icon 图标的 SVG ,以 iconfont 为例,你可以通过它的官方网站搜索并下载SVG格式的图标或插图。

从平台上复制过来的图标对应的 SVG 代码如下:

SVG
<svg t="1707272090280" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="7471" width="200" height="200">
    <path d="M694.857143 121.904762c75.751619 0 137.142857 61.635048 137.142857 137.679238s-61.391238 137.679238-137.142857 137.679238a136.46019 136.46019 0 0 1-97.596953-40.96l-95.524571 71.948191c6.38781 18.310095 9.99619 37.936762 10.24 58.368l157.013333 52.540952a114.054095 114.054095 0 0 1 94.427429-50.102857c63.146667 0 114.297905 51.370667 114.297905 114.736762s-51.175619 114.736762-114.297905 114.736762c-62.780952 0-113.737143-50.834286-114.273524-113.737143l-0.048762 0.243809-149.284571-49.93219a183.905524 183.905524 0 0 1-47.250286 69.412571l70.777905 94.72a91.599238 91.599238 0 0 1 102.936381 91.062857A91.599238 91.599238 0 0 1 534.869333 902.095238a91.599238 91.599238 0 0 1-91.428571-91.794286c0-21.479619 7.363048-41.252571 19.699809-56.905142l-69.193142-92.623239a181.808762 181.808762 0 0 1-64.780191 11.849143c-100.985905 0-182.857143-82.16381-182.857143-183.588571 0-101.376 81.871238-183.56419 182.857143-183.564191 54.979048 0 104.301714 24.380952 137.801143 62.902858l95.719619-72.045715a138.313143 138.313143 0 0 1-4.949333-36.742095C557.714286 183.53981 619.105524 121.904762 694.857143 121.904762z m-160.012191 665.453714a22.918095 22.918095 0 0 0-22.844952 22.942476c0 12.678095 10.24 22.942476 22.869333 22.942477a22.918095 22.918095 0 0 0 22.844953-22.918096 22.918095 22.918095 0 0 0-22.869334-22.966857z m228.571429-229.473524a45.81181 45.81181 0 0 0-45.714286 45.909334c0 25.35619 20.48 45.884952 45.714286 45.884952a45.81181 45.81181 0 0 0 45.714286-45.884952c0-25.35619-20.455619-45.909333-45.689905-45.909334zM329.142857 374.296381c-63.122286 0-114.297905 51.395048-114.297905 114.761143 0 63.366095 51.2 114.736762 114.297905 114.736762 63.122286 0 114.297905-51.370667 114.297905-114.736762 0-63.390476-51.2-114.736762-114.297905-114.736762z m365.714286-183.53981a68.705524 68.705524 0 0 0-68.583619 68.827429c0 38.034286 30.72 68.85181 68.583619 68.85181a68.705524 68.705524 0 0 0 68.583619-68.85181c0-38.034286-30.72-68.827429-68.583619-68.827429z" p-id="7472"></path>
</svg>

你也可以从 Undraw 获取以 .svg 提供的免费开源插图。当你在 unDraw 上选择一幅图像时,你可以更改其颜色并选择下载格式。

使用文本编辑器打开从 unDraw 下载下来的 .svg 文件,你将看到绘制图形的 SVG 代码:

虽然以这种方式获取 SVG 最便利,但需要注意相应的版权问题,另外还有一个明显的缺陷就是,通过在线平台不一定能获得你需要的 SVG 图形。

SVG 与 CSS 之间的关系

现在你已经知道什么是 SVG,也知道可以通过哪些方式获取 SVG。不过,在开始聊 SVG 动画之前,我还是想再花点时间和篇幅与大家聊聊 SVG 与 CSS 之间的关系。

前面提到过,SVG 是类似于 HTML 的一种标记语言。我们同样可以通过 CSS 来给 SVG 元素设置样式,甚至是动画效果。例如下面这个示例,我们利用 CSS 的 currentColor 来处理 SVG 图形的填充颜色。

使用 SVG 绘制的形状,通常以两种方式呈现,一种是实心(例如纯色填充图形),一种是空心的(例如只有纯色轮廓线)。例如下面这两个图标:

它们对应的 SVG 代码如下所示:

SVG
<!-- 实心 -->
<svg t="1707273268154" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="8549" width="200" height="200">
    <path fill="#272636" d="M780.8 204.8c-83.2-44.8-179.2-19.2-243.2 44.8L512 275.2 486.4 249.6c-64-64-166.4-83.2-243.2-44.8C108.8 275.2 89.6 441.6 185.6 537.6l32 32 153.6 153.6 102.4 102.4c25.6 25.6 57.6 25.6 83.2 0l102.4-102.4 153.6-153.6 32-32C934.4 441.6 915.2 275.2 780.8 204.8z"  p-id="8550"></path>
</svg>

<!-- 轮廓 -->
<svg t="1707273579095" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="8827" width="200" height="200">
    <path fill="#272636" d="M797.184 518.496l-284.384 294.016-284.16-292A162.752 162.752 0 0 1 192 417.6C192 328.512 263.808 256 352 256a159.36 159.36 0 0 1 133.28 72.16L512 368.64l26.72-40.48A159.488 159.488 0 0 1 672 256c88.224 0 160 72.512 160 161.6 0 37.536-12.992 74.08-34.816 100.896M672 192a222.72 222.72 0 0 0-160 67.712A222.624 222.624 0 0 0 352 192c-123.52 0-224 101.216-224 225.6 0 52.288 18.176 103.232 52.96 145.536l285.952 293.984a62.4 62.4 0 0 0 45.088 19.168c17.12 0 33.12-6.816 45.12-19.136l287.744-296.064A226.816 226.816 0 0 0 896 417.6C896 293.216 795.52 192 672 192"  p-id="8828"></path>
</svg>

现在,我们需要制作一个点赞按钮。例如,将上图实心的心形图标放到按钮中:

HTML
<button class="button">
    <svg t="1707273268154" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="8549" width="200" height="200">
        <path fill="#272636" d="M780.8 204.8c-83.2-44.8-179.2-19.2-243.2 44.8L512 275.2 486.4 249.6c-64-64-166.4-83.2-243.2-44.8C108.8 275.2 89.6 441.6 185.6 537.6l32 32 153.6 153.6 102.4 102.4c25.6 25.6 57.6 25.6 83.2 0l102.4-102.4 153.6-153.6 32-32C934.4 441.6 915.2 275.2 780.8 204.8z"  p-id="8550"></path>
    </svg>
    Like
</button>

我们会给按钮添加背景和文本颜色来简单的美化按钮。例如:

CSS
button {
    --background-color: #ff5722;
    color: #fff;
    background-color: var(--background-color);
   
    &:hover {
      --background-color: #be3a10;
    }
    
    svg {
        display: block;
        width: 1.5em;
        height: 1.5em;
    }
}

你会发现,黑色(#272636)心形图标能很好的适应按钮,但它的颜色不对:

Demo 地址:https://codepen.io/airen/full/YzgjVZj

回过头来看心形图标对应的 SVG 代码:

SVG
<!-- 实心 -->
<svg t="1707273268154" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="8549" width="200" height="200">
    <path fill="#272636" d="M780.8 204.8c-83.2-44.8-179.2-19.2-243.2 44.8L512 275.2 486.4 249.6c-64-64-166.4-83.2-243.2-44.8C108.8 275.2 89.6 441.6 185.6 537.6l32 32 153.6 153.6 102.4 102.4c25.6 25.6 57.6 25.6 83.2 0l102.4-102.4 153.6-153.6 32-32C934.4 441.6 915.2 275.2 780.8 204.8z"  p-id="8550"></path>
</svg>

不难发现,SVG 图标的 <path> 元素上有一个 fill 属性,并且它的值为 #272636 ,即 <path fill="#272636" ``/>fill 所起的作用是,使用指定的 #272636 颜色来填充整个路径。我们希望的是,按钮上的“心形”图标的颜色能与按钮的文本颜色(color)相同。除了修改 <path>fill 属性值之外,还可以使用 CSS 覆盖 fill 的值:

CSS
.icon * {
    fill: #fff;
}

你也可以使用 CSS 自定义属性来定义:

CSS
button {
    --text-color: #fff;
    
    color: var(--text-color);
    
    svg * {
        fill: var(--text-color);
    }
}

Demo 地址:https://codepen.io/airen/full/PoLdqJV

我们已经成功将按钮的文本颜色应用到 SVG 图标。然而,这并不是一个理想的解决方案,svg * 选择器将会覆盖 <svg> 所有子元素的 fill 值,在某些场景中,这可能并不符合 Web 开发者的需求。较好的一个方案是利用 CSS 的 currentColor 来调整 SVG 图标的颜色,因为 currentColor 的值等于元素的 color 属性的值。如此一来,我们就可以通过改变 CSS 的 color 的值来更改 SVG 的 fill 属性的值。

不过,这样做有一个前提条件,需要将 SVG 的元素上的 fill 属性设置为 currentColor

SVG
<!-- 未使用 currentColor -->
<svg t="1707273268154" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="8549" width="200" height="200">
    <path fill="#272636" d="M780.8 204.8c-83.2-44.8-179.2-19.2-243.2 44.8L512 275.2 486.4 249.6c-64-64-166.4-83.2-243.2-44.8C108.8 275.2 89.6 441.6 185.6 537.6l32 32 153.6 153.6 102.4 102.4c25.6 25.6 57.6 25.6 83.2 0l102.4-102.4 153.6-153.6 32-32C934.4 441.6 915.2 275.2 780.8 204.8z"  p-id="8550"></path>
</svg>

<!-- 使用 currentColor -->
<svg t="1707273268154" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="8549" width="200" height="200">
    <path fill="currentColor" d="M780.8 204.8c-83.2-44.8-179.2-19.2-243.2 44.8L512 275.2 486.4 249.6c-64-64-166.4-83.2-243.2-44.8C108.8 275.2 89.6 441.6 185.6 537.6l32 32 153.6 153.6 102.4 102.4c25.6 25.6 57.6 25.6 83.2 0l102.4-102.4 153.6-153.6 32-32C934.4 441.6 915.2 275.2 780.8 204.8z"  p-id="8550"></path>
</svg>

这样做的一个好处是,当 SVG 填充颜色需要匹配文本颜色并响应各种状态,比如悬停和焦点时,这非常方便。

CSS
button {
    --background-color: #ff5722;
    --text-color: #fff;
    
    &:hover {
      --background-color: #be3a10;
      --text-color: oklch(0.85 0.2 101.5);
    }

    &:focus:not(:focus-visible) {
      --background-color: oklch(0.47 0.12 62.95);
      --text-color: oklch(0.81 0.22 116.71);
    }
}

Demo 地址:https://codepen.io/airen/full/yLwxNqJ

其实,SVG 元素上的很多属性都可以通过 CSS 样式来覆盖,例如:

SVG
<svg t="1707273268154" viewBox="0 0 200 200" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="8549" width="200" height="200">
    <circle cx="100" cy="100" r="90" />
</svg>
CSS
circle {
    fill: red;
    stroke: lime;
    stroke-width: 10;
    stroke-dasharray: 20 5;
    stroke-dashoffset: 50;
}

Demo 地址:https://codepen.io/airen/full/PoLyJKa

正如你所看到的,SVG 和 CSS 是两种不同但常常一起使用的技术,它们在 Web 开发中有着密切的关系。它们共同为 Web 开发者提供了强大的工具,使其能够创建交互性强、响应式的矢量图形。通过结合使用这两项技术,Web 开发者可以创造出富有创意和表现力的 Web图形和动画。

SVG 动画

SVG 动画可以为你的矢量图形增添生气,使你的 Web 体验更具交互性和吸引力。你可以通过动画化 SVG 形状、描边和变换,创造出从弹跳的球到复杂的信息图表和运动图形的各种效果。

在本质上,SVG 动画涉及对 SVG 元素的不同方面进行动画处理,如形状、描边、填充和变换等。通过随时间操作这些属性,Web 设计师和开发人员可以实现各种效果,从简单的过渡到复杂的运动图形。

在 Web 中给 SVG 添加动画,常见的方式主要有:

  • SMIL 动画:利用 SVG 动画标准和 SMIL 动画语言。可以使用 <animate><animateTransform> 元素来创建SMIL动画
  • CSS 动画:使用 CSS 动画,这是一种兼容 HTML 和 SVG 元素的前沿方法。 使用 CSS 的 @keyframesanimationtransition属性,你可以动画化 SVG 的属性,如描边(stroke)、填充(fill)和变换(transform)等
  • WAAPI 动画:这个有点类似于 CSS 动画,通过 WAAPI 提供的相关 API 来动画化 SVG 的属性

SVG 动画标准SMIL 动画语言提供了一种强大的方法来赋予 SVG 元素生命。它涉及使用 <animate> 元素以及 SMIL 语法来定义动画属性及其值。这种方法允许精确控制时间和缓动函数,产生平滑而无缝的动画。然而,值得注意的是,SMIL 动画正在逐渐被淘汰,可能在所有的浏览器中得不到广泛支持。

另一方面,CSS 动画(transitionanimation)因其对 SVG 元素的动画效果而受到欢迎。它们提供了一种更灵活且广泛支持的方法。通过 CSS 动画,可以使用关键帧和各种 CSS 属性(如 @keyframestransitionanimation)来为 SVG 属性添加动画效果。这使得更容易与现有的 CSS 集成,并提供对动画效果的广泛控制。 CSS 动画还可以无缝地与 HTML 和 SVG 元素一起使用,使其成为动画 SVG 图形的多功能选择。

除此之外,我们还可以使用 WAAPI 提供的丰富的 API 来动画化 SVG 元素的属性,从而给 SVG 添加动画效果。这一点与 CSS 动画化 SVG 属性非常相似。不同的是,WAAPI 提供了更多控制动画的 API,而且这些 API 都是源于浏览器动画引擎,在性能方面具有先天的优势。

简而言之,在 Web 上,我们可以使用 SMIL、CSS 和 WAAPI 给 SVG 元素添加动画效果。但在选择技术时,了解每种技术的优势和劣势非常重要。SMIL 动画提供了精确的控制,但浏览器支持有限;CSS 动画提供了更广泛的兼容性,但在控制动画播放方式有着一定的缺陷性;WAAPI 提供了更多制作和控制动画的 API,但需要一定的 JavaScript 知识。

SVG 动画为增强 Web 应用或网页设计提供了无尽的可能性。它使 Web 设计师或开发者创建引人入胜和交互式的视觉效果,从微妙的过渡动画到复杂的叙事动画。它特别适用于传达信息、说明概念或引导用户使用 Web 应用。

SVG 动画的例子有很多,包括形状之间的变形、通过动画路径创建复杂的插图或信息图表、模拟弹跳或脉动元素的动态效果,以及通过带有动画按钮或交互元素的交互式用户界面。

此外,SVG 动画还具有一些很棒的优势。其中一个很酷的事情是,它可能被放大到无限,而不会变得模糊或呈现像素化。与常规图像不同,SVG 图形是矢量的,因此无论你将它们如变得多么大或小,它们都能保持清晰。这意味着动画图形将在任何设备上都看起来很棒。

SVG 动画的另一个很棒之处在于,它不会占用你的文件空间。与其他图像格式相比, SVG 文件通常较小,这意味着它们加载更快,使你的 Web 应用或网站运行更顺畅。因此,你可以在不牺牲速度或让用户感到恼火的情况下拥有酷炫的动画。

SVG 动画让你可以发挥创造力,按照自己的方式进行操作。你可以调整颜色、大小、时间和物体移动方式,以创建独特和个性化的动画。

而且,SVG 动画对残障人士也非常友好。它与辅助技术能完美配合,因此每个人都可以享受你的动画内容。通过添加文本描述并正确管理焦点,SVG 动画使 Web 对于每个人都变得更具包容性和可访问性。

总而言之,SVG 动画是一种令人惊叹的技术,将乏味的适量图形转化为令人兴奋和交互式的体验。无论你使用带有 SMIL 的 SVG 动画标准还是 CSS 动画,还是 WAAPI 动画,都可以通过平滑的过渡、酷炫的效果和用户互动,为你的创作赋予生命。凭借其可伸缩性、文件小、定制灵活和无障碍兼容性,SVG 动画是使你的 Web 应用或网站在视觉上令人惊叹且用户友好的必备工具。随着 Web 的不断发展,SVG 动画将继续在数字世界中展现引人入胜和吸引人的体验!

使用 transition 进行动画

众所周知,你可以使用 CSS 的 transition 对各种属性进行动画化来创建动态的视觉效果。虽然并非每个属性都是“可动画化的”,但许多属性可以使用 CSS 与 SVG 无缝过渡或动画。例如,通过使用 transformopacitycolor 等属性,将静态 SVG 转换为具有动态效果的 SVG。

以常见的“汉堡菜单图标”为例:

这是一个微妙但有价值的动画,它引起用户的注意,告诉他们该图标可用于关闭菜单。现在,我们也用 SVG 和 CSS 的 transition 来制作一个类似的带有动画效果的“汉堡菜单图标”。当用户鼠标悬浮(或点击)图标时,它将转变为关闭图标。

先从 SVG 结构开始,将使用三个 SVG 的 <rect> 元素绘制“汉堡菜单图标”。第一个表示顶部条,第二个表示中间条,最后一个表示底部条:

SVG
<svg xmlns="http://www.w3.org/2000/svg" class="icon--hamburger" width="64" height="64" viewBox="0 0 48 48">
    <rect class="hamburger__top" x="0" y="0" rx="4" ry="4" width="100%" height="8" />
    <rect class="hamburger__middle"  x="0" y="20"  rx="4" ry="4" width="100%" height="8" />
    <rect class="hamburger__bottom"  x="0" y="40"  rx="4" ry="4" width="100%" height="8" />
</svg>

现在,我们可以使用 viewBox 属性建立一个坐标系统,提供默认的xywidthheight。我们设置 widthheight 属性以实现尺寸的灵活性,解决FOUS(无样式闪烁)。我们使用 xy 坐标定位条形,使用 rxry<rect> 绘制圆角,分配高度,并使用 100% 的宽度。我们通过设置等间距的 y 坐标来有策略地堆叠条形。

在 CSS 部分,我们定义自定义属性,如图标大小和条形高度:

CSS
:root {
    --icon-size: 48;
    --icon-bar-size: 8;
}

我们的正方形 SVG 的边长为 64px。对于关闭图标动画,将变换原点设置为顶部和底部条的中心,以避免由于对角线长度而导致的故障。

沿 y 轴平移条形以保持居中,调整元素高度。确定所需的 y 轴平移距离并设置过渡持续时间:

CSS
:root {
    --icon-size: 48;
    --icon-bar-size: 8;
    --icon-translation-size: calc((var(--icon-size) - var(--icon-bar-size)) / 2);
    --icon-transition-duration: 300ms;
  }

接下来,配置过渡并将 ease-in-out 作为过渡函数应用于菜单条,以增强从内到外的过渡。

如前所述,将变换原点设置为中心是至关重要的。为此,我们必须为顶部和底部条的悬停状态设置 transform-origin 属性的值为 center

CSS
.icon--hamburger {
    rect {
        transition: all var(--icon-transition-duration) ease-in-out; 
    }
    
    &:hover {
        :is(.hamburger__top, .hamburger__bottom) {
            transform-origin: center; 
        }
    }
}

将顶部条(.hamburger__top)顺时针旋转 45deg 度,底部条(.hamburger__bottom)逆时针旋转 45deg度。在动画期间通过将中间条(.hamburger__middle)的不透明度(opacity)设置为 0 来隐藏它。我们可以将这些变换应用于 SVG 形状的悬停状态或可切换的类,为简单起见,可以在CSS中使用悬停伪类:

CSS
.icon--hamburger {
    &:hover {
        .hamburger__top {
            transform: rotate(45deg) translate(0, calc(var(--icon-translation-size) * 1px));
        }
        
        .hamburger__bottom {
            transform: rotate(-45deg) translate(0, calc(var(--icon-translation-size) * -1px));;
        }
        
        .hamburger__middle {
            opacity: 0;
        }
    }
}

在此基础上,还可以对 <rect> 元素的 fill 属性进行动画化:

CSS
:root {
    --icon-color: #747d8c;
    --icon-active-color: #2ed573;
}

.icon--hamburger {
    color: var(--icon-color);
    
    rect {
        fill: currentColor
    }

    &:hover {
        rect {
            fill: var(--icon-active-color);
        }
    }
}

你最终看到的效果如下:

Demo 地址:https://codepen.io/airen/full/wvORBRJ

以同样的原理,我们还可以将“汉堡菜单图标”变换为其他的图标,例如 @jgnacademy 在 Codepen 上写的示例

Demo 地址:https://codepen.io/jgnacademy/full/JjvgVEj

使用 animation 进行动画

除了使用 CSS 的 transition 给 SVG 添加动画之外,还可以通过使用 CSS 的 @keyframes 规则,定义一系列关键帧,这些关键帧将 SVG 元素转换为为引人入胜的动画。例如,下面这个加载动画,使用 SVG 和 CSS 一起来创建是相当简单的。

只需要使用 SVG 的 <circle> 元素绘一个带有透明度填充和 4px 描边的圆,然后使用 cxcy 属性将其精确定位在 SVG 的中心位置。然后,考虑描边宽度(stroke-width)调整圆的半径 r ,具体的 SVG 代码如下:

SVG
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="64" height="64" class="spinner">
    <circle cx="24" cy="24" r="22" fill="transparent" stroke-width="4" />
</svg>

使用CSS关键帧,将动画从 0deg 旋转到 360de度,创建一个完整的旋转。使用CSS设置SVG元素的 animation 属性,应用线性操作和无限循环,持续一秒:

CSS
:root {
    --spinner-animation-speed: 1s;
}

@keyframes spin {
    from {
        rotate:0deg;
    }
    to {
      rotate:360deg;
    }
}

.spinner {
    animation: spin var(--spinner-animation-speed) linear infinite;
}

为了增强动画效果,使用 SVG 的 linearGradientstop 元素引入渐变效果。在 linearGradient 元素中调整值,如 x1x2y1y2stop-colorstop-opacity,以尝试创建各种加载旋转器变体:

SVG
<svg xmlns="http://www.w3.org/2000/svg" width="64" height="64" viewBox="0 0 48 48" class="spinner">
    <defs>
        <linearGradient id="gradientFade" x1="20%" x2="50%" y1="60%" y2="100%">
            <stop offset="0%" class="spinner-gradient-stop" />
            <stop offset="25%" stop-opacity="75%" class="spinner-gradient-stop" />
            <stop offset="50%" stop-opacity="50%" class="spinner-gradient-stop" />
            <stop offset="75%" stop-opacity="25%" class="spinner-gradient-stop" />
            <stop offset="100%" stop-opacity="5%" class="spinner-gradient-stop" />
        </linearGradient>
    </defs>
    <g>
        <circle cx="24" cy="24" r="22" fill="transparent" stroke="url(#gradientFade)" stroke-width="4" />
    </g>
</svg>

为每一个 <stop> 元素设置一个类,例如 .spinner-gradient-stop ,以便 CSS 设置样式,例如在 CSS 中覆盖 <stop> 元素的 stop-color 属性的值。最终效果的 CSS 代码如下:

CSS
@layer demo {
    :root {
        --spinner-animation-speed: 1s;
        --spinner-color: #8854d0;
    }

    @keyframes spin {
        from {
            rotate: 0deg;
        }
        to {
            rotate: 360deg;
        }
    }

  .spinner {
      fill: currentColor;

      animation: spin var(--spinner-animation-speed) linear infinite;

      .spinner-gradient-stop {
          stop-color: var(--spinner-color);
      } 
    }
}

最终呈现给你的效果如下:

Demo 地址:https://codepen.io/airen/full/LYaMVZV

要是你对 SVG 有足够深的认识,那么还可以制作一些更微妙的动画效果,例如下面这人导航菜单的效果:

Demo 地址:https://codepen.io/milanraring/full/qBEPzKB (来源于 @Milan Raring

还可以制作一些强交互性的动画效果:

Demo 地址:https://codepen.io/agathaco/full/NyQgQX (来源于 @agathaco

也可以给一些 SVG 插画添加动画效果:

Demo 地址:https://codepen.io/uttammahat/full/NorNeR (来源于 @Uttam

甚至还可以结合 SVG 的滤镜特性创作出一些更高级,更复杂和更微妙的动画效果,例如下面这个导航栏的效果:

Demo 地址:https://codepen.io/v_Bauer/full/WNroMOq (来源于 @Vadim Bauer

上面所展示的动画看上去似乎比较复杂,但并没有大家想象的那么复杂,如果你对 SVG 和 CSS 动画相关的知识较为了解,创作这些动画还是手到擒来!我们在后面的课程上还会详细与大家一起探讨 CSS 如何给 SVG 添加动画。

使用 WAAPI 进行动画

简单地说,WAAPI 给 SVG 元素添加动画就像是 CSS 给 SVG 动画添加元素,只不过它是使用 JavaScript API 来完成。例如前面那个圆形加载动画效果,要是使用 WAAPI 的话,可以像下面这样添加动画:

SVG
<svg xmlns="http://www.w3.org/2000/svg" width="64" height="64" viewBox="0 0 48 48" class="spinner">
    <defs>
        <linearGradient id="gradientFade" x1="20%" x2="50%" y1="60%" y2="100%">
            <stop offset="0%" class="spinner-gradient-stop" />
            <stop offset="25%" stop-opacity="75%" class="spinner-gradient-stop" />
            <stop offset="50%" stop-opacity="50%" class="spinner-gradient-stop" />
            <stop offset="75%" stop-opacity="25%" class="spinner-gradient-stop" />
            <stop offset="100%" stop-opacity="5%" class="spinner-gradient-stop" />
        </linearGradient>
    </defs>
    <g>
        <circle cx="24" cy="24" r="22" fill="transparent" stroke="url(#gradientFade)" stroke-width="4" />
    </g>
</svg>
CSS
@layer demo {
    :root {
        --spinner-color: #8854d0;
    }

    .spinner {
        fill: currentColor;

        .spinner-gradient-stop {
            stop-color: var(--spinner-color);
        }
    }
}
JavaScript
const aniEle = document.querySelector(".spinner");

const spin = [
    {
        rotate: "0deg",
        offset: 0
    },
    {
        rotate: "360deg",
    }
];

const options = {
    duration: 1000,
    easing: "linear",
    iterations: Infinity
};

aniEle.animate(spin, options);

最终呈现给你的动画效果和 CSS 给 SVG 添加动画效果是一样的:

Demo 地址:https://codepen.io/airen/full/bGZOpwa

大家需要知道的是,能够使用 CSS 创建的 SVG 动画效果,同样可以使用 WAAPI 来创作。这里就不做过多的阐述!

使用 SMIL 进行动画

除了 CSS 和 WAAPI 对 SVG 进行动画之外,还可以使用 SMIL 对 SVG 进行动画处理,该方式也是创建动态和交互图形的绝佳方式之一。只不过,在使用 SMIL 进行 SVG 动画时,需要记住以下几点:

  • SMIL 是 W3C 的推荐标准,允许 Web 开发者指定和控制 SVG 动画的精确时序
  • SVG 集成了 SMIL 动画规范中定义的动画特性
  • SMIL 允许你对 SVG 元素的各种属性进行动画处理,如数字属性(xy 等)、变换属性(translateroate )和颜色属性
  • 你还可以创建沿着运动路径或在 SVG 中定义的特定路径的动画
  • 使用 SMIL 进行 SVG 动画提供了可伸缩性、交互性和可访问性等多个优势

要开始使用 SVG 中的 SMIL 动画,你可以定义 SVG 元素和属性,添加动画元素和属性以指定动画行为,设置动画的时间和持续时间,然后预览和测试你的动画。使用 SMIL 可以实现多种动画效果,以下是使用SMIL对SVG元素进行动画处理的示例:

SVG
<svg width="300" height="100">
    <rect x="0" y="0" width="300" height="100" stroke="black" stroke-width="1" />
    <rect x="0" y="50" width="15" height="34" fill="blue" stroke="black" stroke-width="1">
        <animateTransform attributeName="transform" begin="0s" dur="20s" type="rotate" from="0 60 60" to="360 100 60" repeatCount="indefinite" />
    </rect>
</svg>

上面代码中,第二个矩形元素被动画处理以连续旋转 20秒。

SVG
<svg width="100" height="100">
    <circle cx="50" cy="50" r="40" fill="red">
        <animate attributeName="fill" values="red;blue;green;yellow;red" dur="5s" repeatCount="indefinite" />
    </circle>
</svg>

上面代码中,将会动画化改变圆的填充颜色,它会从红色变为蓝色、绿色、黄色,然后再次变给红色,整个过程持续 5s

SVG
<svg width="300" height="300">
    <path id="path" d="M 50 50 L 250 50 L 250 250 L 50 250 L 50 50" stroke="black" fill="none" />
    <rect x="50" y="50" width="50" height="50" fill="blue">
        <animateMotion dur="5s" repeatCount="indefinite">
            <mpath xlink:href="#path" />
        </animateMotion>
    </rect>
</svg>

上面的代码中,矩形将会沿着由 <path> 元素定义的路径移动,整个移动过程持续 5s

SVG
<svg width="100" height="100">
    <polygon points="50,10 70,90 10,40" fill="red">
        <animate attributeName="points" dur="5s" repeatCount="indefinite" values="50,10 70,90 10,40; 10,10 90,10 50,90; 50,10 70,90 10,40" />
    </polygon>
</svg>

上面的代码中,多边形在不断的变换三角形形状状,整个过程持续 5s

上面所展示的仅是 SMIL 动画最基础的部分,不难发现,动画 SVG 元素时,出现了 <animate><animateMotion><animateTransform> 等元素。以 <animate> 元素为例。

使用 <animate> 元素逐渐为 SVG 元素添加动画是一种非常酷且富有想象力的方式。在使用 <animate> 元素时,需要注意以下几点:

  • 使用 <animate> 元素,你可以在一定时间内逐渐动画化特定的 SVG 属性
  • 只需使用 attributeName 属性指定要动画化的属性。例如,如果要动画化圆的位置,请使用 attributeName="cx"和attributeName="cy"
  • values 属性定义了动画期间属性的值。例如,要将矩形的填充颜色从红色动画到蓝色再到绿色,使用 values="red;blue;green"
  • 使用 dur 属性确定动画的持续时间。要进行 5s秒的动画,请使用 dur="5s"
  • repeatCount 属性决定动画应重复多少次。要无限次重复动画,请使用 repeatCount="indefinite"

例如下面这个示,该示例使用 <animate> 元素来动画圆的位置,该圆将会在两个位置之间来回移动,创建了一个活泼有趣的动画效果:

SVG
<svg width="400" height="400" class="animated">
    <circle cx="200" cy="200" r="40" fill="oklch(0.77 0.24 152.51)">
        <animate attributeName="cx" values="200;300;200" dur="2s" repeatCount="indefinite" />
        <animate attributeName="cy" values="200;100;200" dur="2s" repeatCount="indefinite" />
  </circle>
</svg>

Demo 地址:https://codepen.io/airen/full/abMPNEz

在使用 <animate> 元素为 SVG 元素添加动画时,时序属性在控制动画行为方面发挥着至关重要的作用:

  • begin:此属性确定动画何时开始。你可以灵活使用此属性的各种值。你可以指定一个特定的时间、几秒钟,甚至是一个事件触发器。例如,你可以设置 begin="0s" 以立即启动动画,或设置 begin="click" 以在用户点击 SVG 元素时开始
  • dur:此属性设置动画的持续时间。你可以使用不同的值,如秒或毫秒。例如,如果你希望动画持续 5s,可以使用 dur="5s"
  • repeatCount:此属性控制动画播放的重复次数。你可以指定一个具体的数字,或使用值 "indefinite" 使动画无限重复。例如,如果你希望动画重复三次,可以设置 repeatCount="3"
  • repeatDur:此属性确定动画的总持续时间,包括所有重复。你可以使用各种值,如秒或毫秒。如果你希望动画持续 20s,包括所有重复,可以使用 repeatDur="20s"
  • end:此属性设置动画的结束时间。你可以灵活使用此属性的不同值,如特定时间、几秒钟,甚至是一个事件触发器。例如,你可以指定 end="10s" 以在 10 秒后结束动画

总的来说,诸如 begindurrepeatCount 等时序属性在控制使用 <animate> 元素为 SVG 元素创建的动画行为方面发挥着至关重要的作用。通过尝试不同的时序值,你可以创建独特而引人入胜的动画,增强网站上整体用户体验。

我们来看一个更具体的案例,使用 SVG 的 <animate> 元素实现“汉堡菜单图标”的变换动画,当你点击“汉堡菜单图标”时,它会动态变换到关闭图标:

Demo 地址:https://codepen.io/airen/full/OJqrXLw

上面效果对应的 SVG 代码如下:

SVG
<svg class="icon--hamburger" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 10 10" stroke="#eee" stroke-width=".6" fill="rgba(0,0,0,0)" stroke-linecap="round" style="cursor: pointer">
    <path d="M2,3L5,3L8,3M2,5L8,5M2,7L5,7L8,7">
        <animate dur="0.2s" attributeName="d" values="M2,3L5,3L8,3M2,5L8,5M2,7L5,7L8,7;M3,3L5,5L7,3M5,5L5,5M3,7L5,5L7,7" fill="freeze" begin="start.begin" />
        <animate dur="0.2s" attributeName="d" values="M3,3L5,5L7,3M5,5L5,5M3,7L5,5L7,7;M2,3L5,3L8,3M2,5L8,5M2,7L5,7L8,7" fill="freeze" begin="reverse.begin" />
    </path>
    <rect width="10" height="10" stroke="none">
        <animate dur="2s" id="reverse" attributeName="width" begin="click" />
    </rect>
    <rect width="10" height="10" stroke="none">
        <animate dur="0.001s" id="start" attributeName="width" values="10;0" fill="freeze" begin="click" />
        <animate dur="0.001s" attributeName="width" values="0;10" fill="freeze" begin="reverse.begin" />
    </rect>
</svg>

总之,<animate> 元素及其时序属性为在 SVG 中创建引人入胜的动画打开了一扇大门。通过掌握这些属性,并尝试不同的值和配置,你将发掘 SVG 动画的全部潜力,使你的 Web 应用或网站在视觉上令人惊叹,并通过提供增强的用户体验让访问者愉悦。

需要知道的是,<animate> 元素只是 SVG 中许多令人惊叹的动画元素之一。其他元素,如 <set><animateTransform> ,提供了更多的动画功能。

Demo 地址:https://codepen.io/aurer/full/ZEJxpO (来源于 @Aurer

你可能想更进一步知道 <animate><animateMotion><animateTransform> 等元素给 SVG 添加动画的更多细节,请不用着急,本系列后面专门有一节课与大家一起探讨这方面的知识。敬请期待!

使用相关工具制作 SVG 动画

很多 Web 开发放弃在 Web 上应用 SVG 以及 SVG 动画主要原因之一是对 SVG 不太了解,或者说使用纯 SVG 绘制一些图形需要很长的时间,甚至不易于绘制出符合需要的图形。针对于这种情形,除了考虑和结合 Web 设计师协作之外,还可以考虑使用自己熟悉的图形编辑软件,例如 Sketch 、Figma 等。这一点在课程开头有介绍过,这里就不再重复累述。

通常情况之下,像 Sketch 和 Figma 图形编辑软件并没有提供制作 SVG 动画的相关功能(除插件之外),因此,有部分 Web 开发者获得相关 SVG 代码,也不易于为其添加动画效果。如果你刚好属于这个系列,那么可以考虑使用 ArtistaSVGatorLottieFile 等工具来辅助你创作 SVG 动画。

SVG Artista

ULR:https://svgartista.net/

你可以通过使用 Artista 学习一些基础知识!它就像 SVG 动画的友好向导,通过教程、指南和示例,你将体验到不同的动画技术,从平滑的过渡到令人惊叹的变形动画。Artista 将通过逐步的说明、代码片段和交互演示,轻松地带你学习 SVG 动画。

SVGator

URL:https://app.svgator.com/

SVGator 是 SVG 舞台上的新星!这个平台致力于使 SVG 动画变得轻而易举。通过友好的工具,你可以在不费吹灰之力的情况下使 SVG 栩栩如生。这对于初学者和专业人士都是完美的,他们希望为设计添加额外的活力。

LottieFiles

URL:https://lottiefiles.com/free-animations/svg

LottieFiles是探索和分享 Lottie 动画的平台,包括基于 SVG 的动画。这就像一个等待着启发你的创意动画的中心。你可以在这里获得很多非常优秀且有创意的 SVG 动画。

小结

SVG(Scalable Vector Graphics)动画基础入门涉及一种基于XML的图形格式,具有可伸缩性和灵活性。要了解 SVG 动画,首先需要熟悉 SVG 基础知识,包括常见的 SVG 元素如 <rect><circle><line><path> 等。SVG 元素通过文本编辑器或图形编辑软件创建,形成二维图形和图形应用程序。

动画可以通过 CSS 和 JavaScript 实现。CSS 动画利用 @keyframes 规则和 animation 属性,定义动画序列。过渡效果通过 transition 属性实现平滑属性值变化。JavaScript 动画则使用 WAAPI 相关 API 或 SVG 的DOM API,通过修改属性值来实现更灵活的动画逻辑。

我们探索了通过使用同步多媒体集成语言(SMIL)对 SVG 进行动画的一种关键方法。SMIL 提供了一种声明性的动画方法,允许我们使用XML语法定义动画。这种方法简化了动画过程,并让我们对时间和同步性具有精确控制,从而产生平滑而同步的动画效果。

我们讨论了 SVG 动画的诸多优势,包括创建平滑的过渡效果,引导用户注意重要元素,并以视觉上令人愉悦的方式呈现复杂信息的能力。SVG 动画使开发人员和设计师能够超越静态图形,创建引人入胜且令用户兴奋的体验。

为了优化 SVG 动画,可以选择合适的动画类型,避免过多或不必要的动画效果,并使用工具如 SVGO 进行 SVG 文件的优化。最终,学习SVG 动画需要结合实践,逐步深化对 SVG 动画的理解和应用,从而应用于网页图形、数据可视化和用户界面等场景。

总而言之,SVG 动画为在 Web 上创建惊人图形打开了全新的可能性。通过了解 SVG 动画的基础知识、它所提供的优势以及涉及的技术,开发人员和设计师可以充分利用这一强大技术,打造引人入胜和沉浸式的用户体验。